﻿using Renci.SshNet;
using Renci.SshNet.Common;
using System;

namespace SimpleTerminal.Session
{
    /// <summary>
    /// Provides client connection to SSH server.
    /// </summary>
    public class SshConnection : IConnection
    {
        private readonly ClientSession clientSession;
        protected bool isConnected = false;

        public SshConnection(string host, string user, string pass)
            : this(host, 22, user, pass)
        {

        }

        protected string host;
        protected int port;

        public SshConnection(string host, int port, string user, string pass)
        {
            this.host = host;
            this.port = port;

            clientSession = new ClientSession(host, port, user, pass);
            clientSession.HostKeyReceived += HostKeyReceived;
            clientSession.Connected += Session_Connected;
            clientSession.Disconnected += Session_Disconnected;
            clientSession.Closed += Session_Closed;
            clientSession.DataReceived += Session_DataReceived;
            clientSession.ErrorOccurred += Session_ErrorOccurred;
        }

        protected void HostKeyReceived(object sender, EventArgs eventArgs)
        {

        }

        protected void Session_DataReceived(object sender, ShellDataEventArgs e)
        {
            OnDataReceived(e.Data);
        }

        protected void Session_Connected(ClientSession clientSession)
        {
            isConnected = true;
            OnConnected();
        }
        protected void Session_Disconnected(ClientSession clientSession)
        {
            isConnected = false;
            OnDisconnected();
        }

        protected void Session_ErrorOccurred(object sender, ExceptionEventArgs args)
        {
            //Log.Debug("xx",args.Exception.Message);
            //BeginDisconnect();
            OnError(Errors.CONNECT_ERROR, args.Exception.Message);
        }

        protected void Session_Closed(ClientSession clientSession)
        {
            BeginDisconnect();
        }

        public override void Connect()
        {
            OnConnecting(host + ":" + port);
            try
            {
                clientSession.Connect();
            }
            catch (System.Net.Sockets.SocketException e)
            {
                switch (e.ErrorCode)
                {
                    case 10061:
                        OnError(Errors.WSAECONNREFUSED, "因为目标主机积极拒绝此链接，无法成功连接");
                        break;
                    default:
                        OnError(Errors.CONNECT_ERROR, e.Message);
                        break;
                }
            }
            catch (SshAuthenticationException)
            {
                OnError(Errors.AUTH_ERROR, "认证失败");
            }
        }

        public override void Disconnect()
        {
            clientSession.Disconnect();
        }

        public override SessionType GetSessionType()
        {
            return SessionType.Ssh;
        }

        public override void Send(string text)
        {
            try
            {
                if (Canwrite)
                {
                    clientSession.Write(text);
                }
            }
            catch (SshConnectionException)
            {

            }
        }

        public override void SendWindowChangeRequest(int columns, int rows, int width, int height)
        {
            if (clientSession != null)
                clientSession.Stream.SendWindowChangeRequest((uint)columns, (uint)rows, (uint)width, (uint)height);
        }


        public override void SendKeepAlive()
        {
            clientSession.SendKeepAlive();
        }

        public override bool IsConnected()
        {
            return isConnected && clientSession.IsConnected;
        }
    }

}
